home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / domain.c < prev    next >
C/C++ Source or Header  |  1992-08-20  |  24KB  |  1,122 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <time.h>
  4. #if defined(UNIX) || defined(GNUC)
  5. #include <string.h>
  6. #endif
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "netuser.h"
  10. #include "timer.h"
  11. #include "udp.h"
  12. #include "cmdparse.h"
  13. #include "domain.h"
  14.  
  15.  
  16. #ifndef _STRING_H
  17. char *strchr(), strrchr(), *strdup();
  18. #endif
  19.  
  20. void drx(),drx_init();
  21. extern int errno;
  22. extern int32 Ip_addr;
  23.  
  24. struct rr *Rrlist[NRLIST];
  25. struct dserver *Dlist;        /* List of potential servers */
  26. struct dserver *Dserver;    /* Current one being used */
  27. char *Dsuffix;            /* Default suffix for names without periods */
  28. struct socket Dsocket;        /* Socket to use for domain queries */
  29. int Dsignal;
  30. int Drx;            /* Drx started? */
  31. int Ddebug = 0;
  32. char *Dtypes[] = {
  33.     "",
  34.     "A",
  35.     "NS",
  36.     "MD",
  37.     "MF",
  38.     "CNAME",
  39.     "SOA",
  40.     "MB",
  41.     "MG",
  42.     "MR",
  43.     "NULL",
  44.     "WKS",
  45.     "PTR",
  46.     "HINFO",
  47.     "MINFO",
  48.     "MX",
  49.     "TXT"
  50. };
  51. int Ndtypes = 17;
  52. static char delim[] = " \t\r\n";
  53. static struct {
  54.     char *name;
  55.     int32 address;
  56. } cache;
  57.  
  58. struct cmds Dcmds[] = {
  59.     "addserver",    doadds,        0, 0, NULLCHAR,
  60.     "dropserver",    dodropds,    0, 0, NULLCHAR,
  61.     "suffix",    dosuffix,    0, 0, NULLCHAR,
  62.     "trace",    dodtrace,    0, 0, NULLCHAR,
  63.     NULLCHAR,    NULLFP,        0, 0, "domain subcommands: addserver dropserver suffix trace",
  64. };
  65. int
  66. dodtrace(argc,argv)
  67. int argc;
  68. char *argv[];
  69. {
  70.     if(argc < 2){
  71.         printf("Domain trace: %s\n",Ddebug ? "On" : "Off");
  72.     } else {
  73.         if(strcmp(argv[1],"on") == 0)
  74.             Ddebug = 1;
  75.         else
  76.             Ddebug = 0;
  77.     }
  78.     return 0;
  79. }
  80. int
  81. dodomain(argc,argv,envp)
  82. int argc;
  83. char *argv[];
  84. char *envp;
  85. {
  86.     return subcmd(Dcmds,argc,argv,envp);    
  87. }
  88. int
  89. dosuffix(argc,argv)
  90. int argc;
  91. char *argv[];
  92. {
  93.     if(argc < 2){
  94.         if(Dsuffix != NULLCHAR)
  95.             printf("%s\n",Dsuffix);
  96.         return 0;
  97.     }
  98.     free(Dsuffix);
  99.     Dsuffix = strdup(argv[1]);
  100.     return 0;
  101. }
  102. int
  103. doadds(argc,argv)
  104. int argc;
  105. char *argv[];
  106. {
  107.     struct dserver *dp;
  108.     int32 address;
  109.  
  110.     if((address = resolve(argv[1])) == 0){
  111.         printf("Resolver %s unknown\n",argv[1]);
  112.         return 1;
  113.     }
  114.     dp = (struct dserver *)calloc(1,sizeof(struct dserver));
  115.     dp->address = address;
  116.     dp->srtt = 5L;
  117.     dp->timeout = dp->srtt * 2;
  118.     dp->mdev = 0;
  119.     dp->next = Dlist;
  120.     if(dp->next != NULLDOM)
  121.         dp->next->prev = dp;
  122.     Dlist = dp;
  123.     Dserver = dp;    /* Make this the first one we try next */
  124.     if(Drx == 0){
  125.         /* Start domain task upon first addserver */
  126.         drx_init();
  127.         Drx = 1;
  128.     }
  129.     return 0;
  130. }
  131. int
  132. dodropds(argc,argv)
  133. int argc;
  134. char *argv[];
  135. {
  136.     struct dserver *dp;
  137.     int32 addr;
  138.  
  139.     addr = resolve(argv[1]);
  140.     for(dp = Dlist;dp != NULLDOM;dp = dp->next)
  141.         if(addr == dp->address)
  142.             break;
  143.  
  144.     if(dp == NULLDOM){
  145.         printf("Not found\n");
  146.         return 1;
  147.     }
  148.     if(dp->prev != NULLDOM)
  149.         dp->prev->next = dp->next;
  150.     else
  151.         Dlist = dp->next;
  152.     if(dp->next != NULLDOM)
  153.         dp->next->prev = dp->prev;
  154.  
  155.     if(Dserver == dp)
  156.         Dserver = Dlist;
  157.     free((char *)dp);
  158.     return 0;
  159. }
  160.  
  161. /* Search local domain file for resource record of specified type.
  162.  * If a record is found, the domain file pointer is left just after it. If
  163.  * not, the file is rewound.
  164.  */
  165. static struct rr *
  166. dfind(dbase,name,type)
  167. FILE *dbase;
  168. char *name;
  169. int type;
  170. {
  171.     struct rr *rrp;
  172.     int nlen;
  173.  
  174.     /* Search file */
  175.     while((rrp = getrr(dbase)) != NULLRR){
  176.         if((nlen = strlen(name)) == strlen(rrp->name)
  177.          && strncasecmp(name,rrp->name,nlen) == 0
  178.          && rrp->class == CLASS_IN
  179.          && rrp->type == type)
  180.             break;
  181.         free_rr(rrp);
  182. /*        pwait(NULL);    /* Give up CPU for a while, this is slow */
  183.     }
  184.     if(rrp == NULLRR)
  185.         rewind(dbase);
  186.     return rrp;
  187. }
  188. static struct rr *
  189. getrr(fp)
  190. FILE *fp;
  191. {
  192.     char *line,*strtok();
  193.     struct rr *rrp;
  194.     char *name,*ttl,*class,*type,*data;
  195.     int i;
  196.  
  197.     line = malloc(256);
  198.     /* Search file */
  199.     while(fgets(line,256,fp),!feof(fp)){
  200.         if(line[0] != '#')
  201.             break;
  202.     }
  203.     if(feof(fp) || (rrp = (struct rr *)calloc(1,sizeof(struct rr))) == NULLRR){
  204.         free(line);
  205.         return NULLRR;
  206.     }
  207.     name = strtok(line,delim);
  208.     ttl = strtok(NULLCHAR,delim);
  209.     class = strtok(NULLCHAR,delim);
  210.     type = strtok(NULLCHAR,delim);
  211.     data = strtok(NULLCHAR,delim);
  212.     
  213.     rrp->name = strdup(name);
  214.     if(!isdigit(ttl[0])){
  215.       /* Optional ttl field is missing; slide the other fields over */
  216.       data = type;
  217.       type = class;
  218.       class = ttl;
  219.       ttl = NULLCHAR;
  220.     } else {
  221.         rrp->ttl = atol(ttl);
  222.     }
  223.     for(i=0;i<NRLIST;i++){
  224.         if(strcmp(type,Dtypes[i]) == 0){
  225.             rrp->type = i;
  226.             break;
  227.         }
  228.     }
  229.     if(strcmp(class,"IN") == 0)
  230.         rrp->class = CLASS_IN;
  231.  
  232.     if(data == NULLCHAR){
  233.         /* Empty record, just return */
  234.         free(line);
  235.         return rrp;
  236.     }
  237.     switch(rrp->type){
  238.     case TYPE_CNAME:
  239.     case TYPE_MB:
  240.     case TYPE_MG:
  241.     case TYPE_MR:
  242.     case TYPE_NS:
  243.     case TYPE_PTR:
  244.     case TYPE_TXT:
  245.         rrp->rdlength = strlen(data);
  246.         rrp->rdata.name = strdup(data);
  247.         break;
  248.     case TYPE_A:
  249.         rrp->rdlength = 4;
  250.         rrp->rdata.addr = aton(data);
  251.         break;
  252.     case TYPE_HINFO:
  253.         rrp->rdlength = strlen(data);
  254.         rrp->rdata.hinfo.cpu = strdup(data);
  255.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  256.             rrp->rdlength += strlen(data);
  257.             rrp->rdata.hinfo.os = strdup(data);
  258.         }
  259.         break;
  260.     case TYPE_MX:
  261.         rrp->rdata.mx.pref = atoi(data);
  262.         rrp->rdlength = 2;
  263.  
  264.         /* Get domain name of exchanger */
  265.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  266.             rrp->rdlength += strlen(data);
  267.             rrp->rdata.mx.exch = strdup(data);
  268.         }
  269.         break;
  270.     case TYPE_SOA:
  271.         /* Get domain name of master name server */
  272.         rrp->rdlength = strlen(data);
  273.         rrp->rdata.soa.mname = strdup(data);
  274.  
  275.         /* Get domain name of irresponsible person */
  276.         if((data = strtok(NULLCHAR,delim)) != NULLCHAR){
  277.             rrp->rdata.soa.rname = strdup(data);
  278.             rrp->rdlength += strlen(data);
  279.         }
  280.         data = strtok(NULLCHAR,delim);
  281.         rrp->rdata.soa.serial = atol(data);
  282.         data = strtok(NULLCHAR,delim);
  283.         rrp->rdata.soa.refresh = atol(data);
  284.         data = strtok(NULLCHAR,delim);
  285.         rrp->rdata.soa.retry = atol(data);
  286.         data = strtok(NULLCHAR,delim);
  287.         rrp->rdata.soa.expire = atol(data);
  288.         data = strtok(NULLCHAR,delim);
  289.         rrp->rdata.soa.minimum = atol(data);
  290.         rrp->rdlength += 20;
  291.         break;
  292.     }
  293.     free(line);
  294.     return rrp;
  295. }
  296. /* Search for address record in local database, looking first for PTR
  297.  * and CNAME records. Return values:
  298.  *  0xffffffff    Not found (domain name may exist, but we don't know yet)
  299.  *  0        Domain name definitely doesn't exist (we have a null record)
  300.  */
  301. int32
  302. dresolve(name)
  303. char *name;
  304. {
  305.     register struct rr *rrp;
  306.     char *pname = NULLCHAR;
  307.     char *cname = NULLCHAR;
  308.     int32 result;
  309.     FILE *dbase;
  310.  
  311.     if(cache.name != NULLCHAR && strcmp(cache.name,name) == 0)
  312.         return cache.address;
  313.  
  314.     if((dbase = fopen(Dfile,"r")) == NULLFILE)
  315.         return 0xffffffff;
  316.  
  317.     /* This code can handle a few weird cases. It works when there's
  318.      * a PTR to a CNAME to an A record, as well as when there's a
  319.      * a CNAME to a PTR to an A. But it allows only one of each kind
  320.      * of indirection to prevent infinite loops.
  321.      */
  322.     while((rrp = dfind(dbase,name,TYPE_A)) == NULLRR){
  323.         /* An address record didn't exist, let's see if it's an alias */
  324.         if(cname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_CNAME)) != NULLRR){
  325.             if((cname = strdup(rrp->rdata.name)) == NULLCHAR)
  326.                 break;
  327.             name = cname;
  328.             rewind(dbase);
  329.             free_rr(rrp);
  330.             continue;    /* Try again */
  331.         }
  332.         /* Lacking that, try a pointer entry... */
  333.         if(pname == NULLCHAR && (rrp = dfind(dbase,name,TYPE_PTR)) != NULLRR){
  334.             if((pname = strdup(rrp->rdata.name)) == NULLCHAR)
  335.                 break;
  336.             name = pname;
  337.             rewind(dbase);
  338.             free_rr(rrp);
  339.             continue;
  340.         }
  341.         /* Nope, nothing. Give up */
  342.         break;
  343.     }
  344.     fclose(dbase);
  345.     free(pname);
  346.     free(cname);    
  347.  
  348.     if(rrp == NULLRR){
  349.         result = 0xffffffff;        /* No record in database */
  350.     } else {
  351.         if(rrp->rdlength == 0)
  352.             result = 0;        /* Negative response record */
  353.         else
  354.             result = rrp->rdata.addr;    /* Normal return */
  355.         free(cache.name);
  356.         cache.name = strdup(name);
  357.         cache.address = result;
  358.         free_rr(rrp);
  359.     }
  360.     return result;
  361. }
  362. static int numeric_only(char *name)
  363. {
  364.   /* return true if name in in form nnn.nnn.nnn.nnn, where n is 0-9 */
  365.  if(name == (char *) 0  || *name =='\0' ) return(0);
  366.   while( *name ){
  367.     if(*name == '.' || isdigit(*name))  { name++; continue; } 
  368.     return(0);
  369.   }
  370.   return (-1);
  371. }
  372.  
  373. /* Main entry point for domain name -> address resolution. Returns 0 if
  374.  * name is definitely not valid.
  375.  */
  376. int32
  377. resolve(name)
  378. char *name;
  379. {
  380.     char *buf;
  381.     int32 addr;
  382.     struct dserver *dp;
  383.     struct mbuf *bp;
  384.     int len;
  385.     struct socket server;
  386.     char *tname = NULLCHAR;
  387.     char *p